Skip to content

Add generator metadata (wfctl version + plugin versions) to IaC plans and state#625

Merged
intel352 merged 2 commits into
mainfrom
copilot/add-wfctl-version-tracking
May 10, 2026
Merged

Add generator metadata (wfctl version + plugin versions) to IaC plans and state#625
intel352 merged 2 commits into
mainfrom
copilot/add-wfctl-version-tracking

Conversation

Copilot AI commented May 10, 2026

Copy link
Copy Markdown
Contributor

Summary

Tracks the wfctl binary version and the versions of all loaded IaC provider plugins whenever an infrastructure plan or apply operation produces output on disk. This makes it straightforward to know what toolchain version produced a given state artifact and what upgrades may be required when behavior has changed between versions.

Changes

interfaces/iac_state.go

  • Added PluginVersionInfo struct (name, version)
  • Added GeneratorMetadata struct (wfctl_version, plugins []PluginVersionInfo)
  • Added GeneratorMetadata *GeneratorMetadata field to IaCPlan (JSON: generator_metadata, omitempty)

cmd/wfctl/deploy_providers.go

  • Added Name string and Version string fields to iacPluginManifest so the plugin scanner now captures each IaC plugin's declared version from plugin.json

cmd/wfctl/infra_generator_metadata.go (new)

  • buildGeneratorMetadata() — builds a GeneratorMetadata snapshot with the current wfctl version + installed IaC plugin versions
  • collectIaCPluginVersions() — scans WFCTL_PLUGIN_DIR (default ./data/plugins) for subdirectories whose plugin.json declares an iacProvider capability, and returns their name + version

cmd/wfctl/infra.go

  • runInfraPlan: populates plan.GeneratorMetadata before writing plan.json
  • runInfraApply: after a successful apply, calls metadataPersister.SaveMetadata on the state store (best-effort, warns on failure)

cmd/wfctl/infra_state_store.go

  • Added metadataPersister optional interface (SaveMetadata(ctx, GeneratorMetadata) error)
  • Implemented SaveMetadata on fsWfctlStateStore — writes <state-dir>/metadata.json (overwritten on every apply so it reflects the most-recent operation)
  • ListResources now skips metadata.json (alongside the existing .lock.json exclusion)

docs/WFCTL.md

  • Added "Generator metadata" section under infra apply documenting the new generator_metadata field and metadata.json sidecar

cmd/wfctl/infra_generator_metadata_test.go (new)

  • 7 new tests covering: empty plugin dir, non-IaC plugins excluded, IaC plugin captured, mixed plugins, wfctl version always present, SaveMetadata write + ListResources exclusion, overwrite semantics, and IaCPlan JSON round-trip / omitempty

Where the metadata is stored

Operation Metadata location
wfctl infra plan -o plan.json Embedded in plan.json as generator_metadata
wfctl infra apply (filesystem state backend) Written to <state-dir>/metadata.json

Remote backends (Spaces, Postgres) do not yet write a sidecar file; the plan.json covers the primary use case. The metadataPersister optional interface makes it easy to add support to other backends in follow-up PRs.

@github-actions

github-actions Bot commented May 10, 2026

Copy link
Copy Markdown

⏱ Benchmark Results

No significant performance regressions detected.

benchstat comparison (baseline → PR)
## benchstat: baseline → PR
baseline-bench.txt:262: parsing iteration count: invalid syntax
baseline-bench.txt:342677: parsing iteration count: invalid syntax
baseline-bench.txt:655923: parsing iteration count: invalid syntax
baseline-bench.txt:973027: parsing iteration count: invalid syntax
baseline-bench.txt:1469954: parsing iteration count: invalid syntax
baseline-bench.txt:1789617: parsing iteration count: invalid syntax
benchmark-results.txt:262: parsing iteration count: invalid syntax
benchmark-results.txt:336983: parsing iteration count: invalid syntax
benchmark-results.txt:594981: parsing iteration count: invalid syntax
benchmark-results.txt:915625: parsing iteration count: invalid syntax
benchmark-results.txt:1234913: parsing iteration count: invalid syntax
benchmark-results.txt:1570299: parsing iteration count: invalid syntax
goos: linux
goarch: amd64
pkg: github.com/GoCodeAlone/workflow/dynamic
cpu: AMD EPYC 7763 64-Core Processor                
                            │ baseline-bench.txt │        benchmark-results.txt        │
                            │       sec/op       │    sec/op      vs base              │
InterpreterCreation-4              3.334m ± 202%   3.326m ± 195%       ~ (p=0.699 n=6)
ComponentLoad-4                    3.568m ±   2%   3.537m ±   1%  -0.86% (p=0.041 n=6)
ComponentExecute-4                 1.956µ ±   1%   1.922µ ±   1%  -1.74% (p=0.002 n=6)
PoolContention/workers-1-4         1.086µ ±   1%   1.069µ ±   1%  -1.52% (p=0.004 n=6)
PoolContention/workers-2-4         1.079µ ±   6%   1.078µ ±   2%       ~ (p=1.000 n=6)
PoolContention/workers-4-4         1.079µ ±   1%   1.083µ ±   1%       ~ (p=0.379 n=6)
PoolContention/workers-8-4         1.077µ ±   1%   1.080µ ±   1%       ~ (p=0.669 n=6)
PoolContention/workers-16-4        1.085µ ±   3%   1.085µ ±   2%       ~ (p=0.851 n=6)
ComponentLifecycle-4               3.559m ±   1%   3.561m ±   0%       ~ (p=0.937 n=6)
SourceValidation-4                 2.300µ ±   1%   2.279µ ±   1%  -0.89% (p=0.041 n=6)
RegistryConcurrent-4               794.7n ±   3%   799.5n ±   6%       ~ (p=0.937 n=6)
LoaderLoadFromString-4             3.588m ±   2%   3.574m ±   2%       ~ (p=0.240 n=6)
geomean                            17.46µ          17.39µ         -0.37%

                            │ baseline-bench.txt │        benchmark-results.txt         │
                            │        B/op        │     B/op      vs base                │
InterpreterCreation-4               2.027Mi ± 0%   2.027Mi ± 0%       ~ (p=0.974 n=6)
ComponentLoad-4                     2.180Mi ± 0%   2.180Mi ± 0%       ~ (p=0.325 n=6)
ComponentExecute-4                  1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-1-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-2-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-4-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-8-4          1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-16-4         1.203Ki ± 0%   1.203Ki ± 0%       ~ (p=1.000 n=6) ¹
ComponentLifecycle-4                2.183Mi ± 0%   2.183Mi ± 0%       ~ (p=0.195 n=6)
SourceValidation-4                  1.984Ki ± 0%   1.984Ki ± 0%       ~ (p=1.000 n=6) ¹
RegistryConcurrent-4                1.133Ki ± 0%   1.133Ki ± 0%       ~ (p=1.000 n=6) ¹
LoaderLoadFromString-4              2.182Mi ± 0%   2.182Mi ± 0%       ~ (p=0.909 n=6)
geomean                             15.25Ki        15.25Ki       +0.00%
¹ all samples are equal

                            │ baseline-bench.txt │        benchmark-results.txt        │
                            │     allocs/op      │  allocs/op   vs base                │
InterpreterCreation-4                15.68k ± 0%   15.68k ± 0%       ~ (p=1.000 n=6)
ComponentLoad-4                      18.02k ± 0%   18.02k ± 0%       ~ (p=1.000 n=6)
ComponentExecute-4                    25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-1-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-2-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-4-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-8-4            25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
PoolContention/workers-16-4           25.00 ± 0%    25.00 ± 0%       ~ (p=1.000 n=6) ¹
ComponentLifecycle-4                 18.07k ± 0%   18.07k ± 0%       ~ (p=1.000 n=6) ¹
SourceValidation-4                    32.00 ± 0%    32.00 ± 0%       ~ (p=1.000 n=6) ¹
RegistryConcurrent-4                  2.000 ± 0%    2.000 ± 0%       ~ (p=1.000 n=6) ¹
LoaderLoadFromString-4               18.06k ± 0%   18.06k ± 0%       ~ (p=1.000 n=6) ¹
geomean                               183.3         183.3       +0.00%
¹ all samples are equal

pkg: github.com/GoCodeAlone/workflow/middleware
                                  │ baseline-bench.txt │       benchmark-results.txt       │
                                  │       sec/op       │   sec/op     vs base              │
CircuitBreakerDetection-4                  286.4n ± 4%   284.0n ± 4%  -0.82% (p=0.041 n=6)
CircuitBreakerExecution_Success-4          21.55n ± 0%   21.55n ± 2%       ~ (p=1.000 n=6)
CircuitBreakerExecution_Failure-4          66.23n ± 1%   65.59n ± 0%  -0.97% (p=0.002 n=6)
geomean                                    74.21n        73.77n       -0.60%

                                  │ baseline-bench.txt │       benchmark-results.txt        │
                                  │        B/op        │    B/op     vs base                │
CircuitBreakerDetection-4                 144.0 ± 0%     144.0 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Success-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Failure-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                              ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                  │ baseline-bench.txt │       benchmark-results.txt        │
                                  │     allocs/op      │ allocs/op   vs base                │
CircuitBreakerDetection-4                 1.000 ± 0%     1.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Success-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
CircuitBreakerExecution_Failure-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                              ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/module
                                 │ baseline-bench.txt │       benchmark-results.txt        │
                                 │       sec/op       │    sec/op     vs base              │
JQTransform_Simple-4                     905.0n ± 24%   866.5n ± 32%       ~ (p=0.485 n=6)
JQTransform_ObjectConstruction-4         1.431µ ±  0%   1.448µ ±  1%  +1.19% (p=0.002 n=6)
JQTransform_ArraySelect-4                3.276µ ±  2%   3.280µ ±  0%       ~ (p=0.939 n=6)
JQTransform_Complex-4                    38.20µ ±  0%   39.13µ ±  2%  +2.44% (p=0.009 n=6)
JQTransform_Throughput-4                 1.758µ ±  0%   1.758µ ±  2%       ~ (p=0.818 n=6)
SSEPublishDelivery-4                     66.99n ±  7%   67.48n ±  1%       ~ (p=0.394 n=6)
geomean                                  1.635µ         1.635µ        +0.02%

                                 │ baseline-bench.txt │        benchmark-results.txt         │
                                 │        B/op        │     B/op      vs base                │
JQTransform_Simple-4                   1.273Ki ± 0%     1.273Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ObjectConstruction-4       1.773Ki ± 0%     1.773Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ArraySelect-4              2.625Ki ± 0%     2.625Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Complex-4                  16.22Ki ± 0%     16.22Ki ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Throughput-4               1.984Ki ± 0%     1.984Ki ± 0%       ~ (p=1.000 n=6) ¹
SSEPublishDelivery-4                     0.000 ± 0%       0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                             ²                 +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                 │ baseline-bench.txt │       benchmark-results.txt        │
                                 │     allocs/op      │ allocs/op   vs base                │
JQTransform_Simple-4                     10.00 ± 0%     10.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ObjectConstruction-4         15.00 ± 0%     15.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_ArraySelect-4                30.00 ± 0%     30.00 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Complex-4                    324.0 ± 0%     324.0 ± 0%       ~ (p=1.000 n=6) ¹
JQTransform_Throughput-4                 17.00 ± 0%     17.00 ± 0%       ~ (p=1.000 n=6) ¹
SSEPublishDelivery-4                     0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                             ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/schema
                                    │ baseline-bench.txt │       benchmark-results.txt       │
                                    │       sec/op       │   sec/op     vs base              │
SchemaValidation_Simple-4                    1.108µ ± 3%   1.117µ ± 5%       ~ (p=0.452 n=6)
SchemaValidation_AllFields-4                 1.670µ ± 7%   1.662µ ± 2%       ~ (p=0.394 n=6)
SchemaValidation_FormatValidation-4          1.573µ ± 4%   1.583µ ± 2%       ~ (p=0.411 n=6)
SchemaValidation_ManySchemas-4               1.834µ ± 3%   1.841µ ± 2%       ~ (p=0.329 n=6)
geomean                                      1.520µ        1.525µ       +0.33%

                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │        B/op        │    B/op     vs base                │
SchemaValidation_Simple-4                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_AllFields-4                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_FormatValidation-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_ManySchemas-4              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

                                    │ baseline-bench.txt │       benchmark-results.txt        │
                                    │     allocs/op      │ allocs/op   vs base                │
SchemaValidation_Simple-4                   0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_AllFields-4                0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_FormatValidation-4         0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
SchemaValidation_ManySchemas-4              0.000 ± 0%     0.000 ± 0%       ~ (p=1.000 n=6) ¹
geomean                                                ²               +0.00%               ²
¹ all samples are equal
² summaries must be >0 to compute geomean

pkg: github.com/GoCodeAlone/workflow/store
                                   │ baseline-bench.txt │        benchmark-results.txt        │
                                   │       sec/op       │    sec/op     vs base               │
EventStoreAppend_InMemory-4                1.144µ ± 14%   1.101µ ± 35%        ~ (p=0.937 n=6)
EventStoreAppend_SQLite-4                  1.389m ±  4%   1.365m ±  5%        ~ (p=0.240 n=6)
GetTimeline_InMemory/events-10-4           14.48µ ±  4%   13.38µ ±  3%   -7.55% (p=0.002 n=6)
GetTimeline_InMemory/events-50-4           79.45µ ±  3%   76.83µ ±  1%   -3.29% (p=0.015 n=6)
GetTimeline_InMemory/events-100-4          160.9µ ±  4%   136.2µ ± 13%  -15.32% (p=0.002 n=6)
GetTimeline_InMemory/events-500-4          660.2µ ± 13%   635.7µ ±  0%   -3.72% (p=0.002 n=6)
GetTimeline_InMemory/events-1000-4         1.358m ±  1%   1.307m ±  3%   -3.74% (p=0.002 n=6)
GetTimeline_SQLite/events-10-4             109.6µ ±  0%   103.8µ ±  2%   -5.33% (p=0.002 n=6)
GetTimeline_SQLite/events-50-4             258.5µ ±  1%   246.2µ ±  2%   -4.75% (p=0.002 n=6)
GetTimeline_SQLite/events-100-4            435.8µ ±  0%   419.0µ ±  0%   -3.85% (p=0.002 n=6)
GetTimeline_SQLite/events-500-4            1.850m ±  0%   1.804m ±  0%   -2.52% (p=0.002 n=6)
GetTimeline_SQLite/events-1000-4           3.599m ±  0%   3.502m ±  0%   -2.67% (p=0.002 n=6)
geomean                                    229.8µ         218.5µ         -4.92%

                                   │ baseline-bench.txt │        benchmark-results.txt         │
                                   │        B/op        │     B/op      vs base                │
EventStoreAppend_InMemory-4                  805.5 ± 8%     751.0 ± 5%       ~ (p=0.063 n=6)
EventStoreAppend_SQLite-4                  1.984Ki ± 3%   1.987Ki ± 2%       ~ (p=0.249 n=6)
GetTimeline_InMemory/events-10-4           7.953Ki ± 0%   7.953Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-50-4           46.62Ki ± 0%   46.62Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-100-4          94.48Ki ± 0%   94.48Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-500-4          472.8Ki ± 0%   472.8Ki ± 0%       ~ (p=1.000 n=6)
GetTimeline_InMemory/events-1000-4         944.3Ki ± 0%   944.3Ki ± 0%       ~ (p=0.567 n=6)
GetTimeline_SQLite/events-10-4             16.74Ki ± 0%   16.74Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-50-4             87.14Ki ± 0%   87.14Ki ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-100-4            175.4Ki ± 0%   175.4Ki ± 0%       ~ (p=1.000 n=6)
GetTimeline_SQLite/events-500-4            846.1Ki ± 0%   846.1Ki ± 0%       ~ (p=0.197 n=6)
GetTimeline_SQLite/events-1000-4           1.639Mi ± 0%   1.639Mi ± 0%       ~ (p=0.394 n=6)
geomean                                    67.45Ki        67.07Ki       -0.57%
¹ all samples are equal

                                   │ baseline-bench.txt │        benchmark-results.txt        │
                                   │     allocs/op      │  allocs/op   vs base                │
EventStoreAppend_InMemory-4                  7.000 ± 0%    7.000 ± 0%       ~ (p=1.000 n=6) ¹
EventStoreAppend_SQLite-4                    53.00 ± 0%    53.00 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-10-4             125.0 ± 0%    125.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-50-4             653.0 ± 0%    653.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-100-4           1.306k ± 0%   1.306k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-500-4           6.514k ± 0%   6.514k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_InMemory/events-1000-4          13.02k ± 0%   13.02k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-10-4               382.0 ± 0%    382.0 ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-50-4              1.852k ± 0%   1.852k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-100-4             3.681k ± 0%   3.681k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-500-4             18.54k ± 0%   18.54k ± 0%       ~ (p=1.000 n=6) ¹
GetTimeline_SQLite/events-1000-4            37.29k ± 0%   37.29k ± 0%       ~ (p=1.000 n=6) ¹
geomean                                     1.162k        1.162k       +0.00%
¹ all samples are equal

Benchmarks run with go test -bench=. -benchmem -count=6.
Regressions ≥ 20% are flagged. Results compared via benchstat.

@intel352 intel352 marked this pull request as ready for review May 10, 2026 21:52
Copilot AI review requested due to automatic review settings May 10, 2026 21:52

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

Adds “generator metadata” to IaC artifacts produced by wfctl so operators can tell which wfctl binary and IaC provider plugin versions generated a given plan/state output.

Changes:

  • Extend IaC plan schema with generator_metadata (wfctl version + plugin versions).
  • Add generator-metadata collection + persistence: embedded in plan.json, and written as a metadata.json sidecar for filesystem state after apply.
  • Extend IaC plugin manifest parsing to capture plugin name and version, and add tests/docs for the new metadata.

Reviewed changes

Copilot reviewed 7 out of 7 changed files in this pull request and generated 5 comments.

Show a summary per file
File Description
interfaces/iac_state.go Adds PluginVersionInfo / GeneratorMetadata types and embeds generator metadata into IaCPlan.
cmd/wfctl/deploy_providers.go Extends iacPluginManifest to parse plugin name and version from plugin.json.
cmd/wfctl/infra_generator_metadata.go Implements generator metadata snapshotting and IaC plugin version collection.
cmd/wfctl/infra.go Stamps metadata into plan.json and attempts best-effort post-apply metadata persistence to state store.
cmd/wfctl/infra_state_store.go Adds metadataPersister optional interface; filesystem store writes metadata.json and excludes it from ListResources.
cmd/wfctl/infra_generator_metadata_test.go Adds unit tests for plugin scanning, metadata persistence, overwrite behavior, and plan JSON round-trip/omitempty.
docs/WFCTL.md Documents the new generator metadata behavior and storage locations.

Comment thread docs/WFCTL.md Outdated
Comment thread cmd/wfctl/infra_generator_metadata.go Outdated
Comment thread interfaces/iac_state.go Outdated
Comment thread cmd/wfctl/infra.go Outdated
Comment thread cmd/wfctl/infra_state_store.go Outdated
@intel352

Copy link
Copy Markdown
Contributor

@copilot apply changes based on the comments in this thread

Copilot AI commented May 10, 2026

Copy link
Copy Markdown
Contributor Author

@copilot apply changes based on the comments in this thread

Applied all five review points in commit 3ecccc3:

  1. metadata.json format: SaveMetadata now wraps the struct under a "generator_metadata" key, matching plan.json and the docs. Tests updated to assert the wrapper key is present.

  2. "loaded" vs "installed" terminology: Renamed collectIaCPluginVersionscollectInstalledIaCPluginVersions; updated comments in infra_generator_metadata.go and interfaces/iac_state.go to say "installed" with an explicit note that extra installed-but-not-used plugins may appear.

  3. resolveStateStore error warning: The metadata block now emits warning: open state store for metadata: <err> when resolveStateStore fails, not just when SaveMetadata fails.

  4. SaveMetadata comment: Fixed "every apply/plan" → "every apply" since plan-time metadata is handled separately via the plan.json path.

  5. Docs: Expanded "Generator metadata" section to show two distinct examples — plan.json (nested field) and metadata.json (top-level wrapper) — and added a note about "installed" vs "loaded" plugin semantics.

@intel352 intel352 merged commit 27a6fab into main May 10, 2026
24 checks passed
@intel352 intel352 deleted the copilot/add-wfctl-version-tracking branch May 10, 2026 22:58
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants